package require TclOO
package require Thread

oo::class create threaded {
    variable thread
    filter execuate
    constructor args {
	my variable instance
	set class [lindex  [self next] 0]
	set instance [lindex [split [self] ::] end]
	set thread [ thread::create {
	    thread::wait 
	}]
	foreach package [package names] {
	    #puts $package
	   # my require $package
	}
	set cmd {proc existsObj obj {
        if [catch {info object isa object $obj} result] {
         #puts "[thread::id] cannot find $obj"
         return 0
       } else {
         if $result {
           #puts "[thread::id] exist $obj"
           return 1
           } else {
            #puts "[thread::id] $obj is not object"
             return 0
             }
       }}
       proc existsClass obj {
        if [catch {info object isa class $obj} result] {
         #puts "[thread::id] cannot find $obj"
         return 0
       } else {
         if $result {
           #puts "[thread::id] exist $obj"
           return 1
           } else {
            #puts "[thread::id] $obj is not class"
             return 0
             }
       }}
      }
       thread::send $thread $cmd
	my import $class
	my import Interface
	eval [subst {thread::send $thread { $class create $instance  $args } }]
	return $thread
    }

    # filter: put every target method  into thread
    method execuate args {}
    # get result from finished method 
    method finished { method } {}
    
    #load required resources
    method require { package } {}
    method import  class {}
    method copyObj obj {}
    method copyVar { obj varname} {}
    method existsClass c {}
    method existsObj obj {}
    method existsVar var {}


    
    destructor {
	my variable instance
	eval [subst {thread::send $thread { $instance destroy } }]
	thread::release $thread
    }
}

#core utilities
oo::define threaded method execuate args {
    my variable instance
    set target [lindex [self target] 0]
    #skip tcloo core functions
    if { $target eq "::oo::object" } {
	return [next {*}$args]
    }
    set action [lindex [self target] end]
    #skip threaded core functions
    if { [lsearch {finished require import imported existsClass existsObj existsVar copyObj copyVar constructor} $action] >= 0 } {
	return [next {*}$args]
    }
    my variable done_$action
    upvar [my varname done_$action] done
    set done __unfinished__
    eval [subst {thread::send -async $thread { $instance $action $args} [my varname done_$action]}]
}

oo::define threaded method finished { method } {
    upvar [my varname done_$method] result
    if {[string compare $result __unfinished__] != 0} { return $result}
    vwait [my varname done_$method]
    return $result
}
    
#setup package 
oo::define threaded method require { package } {
    eval [subst {thread::send $thread { package require $package} }]
}
##copy the class definition to the thread
oo::define threaded method import class {
    if ![my existsClass $class] { 
      #puts "create $class"
     set cmd "oo::class create $class\n"
    } else {
	set cmd ""
    }
    set variables [info class variables $class]
    foreach v $variables {
	append cmd "oo::define $class variable $v\n"
    }	
    append cmd "oo::define $class constructor [info class constructor $class]\n"
    set body [info class destructor $class]
    if { [llength $body ] > 0} { append cmd "oo::define $class destructor {\n$body \n}\n"}
    set methods [info class methods $class]
    foreach m $methods {
	append cmd "oo::define $class method $m [info class definition $class $m]\n"
    }
    thread::send $thread $cmd
}
##copy the object to the thread
oo::define threaded method copyObj obj {
    #create object if not exists
    if [my existsObj $obj ] { 
	set cmd ""
    } else {
	set class [info object class $obj]
	#import class if do not know class
	if ![my existsClass $class] {
	    my import $class
	}
	set cmd "$class create $obj\n"	    
    }
    set variables [info object vars $obj]
    oo::objdefine $obj export varname
    append cmd "oo::objdefine $obj export varname\n"
    thread::send $thread $cmd
    foreach v $variables {
	my copyVar $obj $v
    }
    
}
##copy the variable to the thread
oo::define threaded method copyVar { obj varname} {
    set var [$obj varname $varname]
    upvar $var Var
    if [array exists Var] {
	thread::send $thread "array set \[$obj varname $varname\] {[array get [$obj varname $varname]]}"
    } else {
	thread::send $thread "upvar \[$obj varname $varname\] Var \n set Var $Var"
    }
}
    
#helper
##Check if a class definition is already existed in a thread. 
oo::define threaded method existsClass c {
    return [thread::send $thread [list existsClass $c]]    
}
##Check if an object definition is already existed in a thread. 
oo::define threaded method existsObj obj {
    
    return [thread::send $thread [list existsObj $obj]]
}
##Check if a variable definition is already existed in a thread. 
oo::define threaded method existsVar var {
    return [thread::send $thread "info exists $var"]
}
